# 参考文章 https://zhuanlan.zhihu.com/p/581650874
from  Ashare import *  

# 下载或读取数据
# 证券代码兼容多种格式 通达信，同花顺，聚宽
# sh000001 (000001.XSHG)    sz399006 (399006.XSHE)   sh600519 ( 600519.XSHG ) 
#df=get_price('000001.XSHG',frequency='1d',count=10000000)      #默认获取今天往前120天的日线行情
#print('上证指数日线行情\n',df.tail(5))
#df.to_csv('000001.XSHG.csv', index=True, encoding='utf-8')
#print("DataFrame已成功保存为CSV文件")
data = pd.read_csv('000001.XSHG.csv')
# 查看数据的前几行，默认显示前5行
#print(data.head())



import talib   

data['ema'] = talib.EMA(data['close'].values, timeperiod=20)
data['stddev']= talib.STDDEV(data['close'].values, timeperiod=20, nbdev=1)
data['slope'] = talib.LINEARREG_SLOPE(data['close'].values, timeperiod=5)
data['rsi'] = talib.RSI(data['close'].values, timeperiod = 14)
data['wr'] = talib.WILLR(data['high'].values, data['low'].values, data['close'].values, timeperiod=7)

print(data.tail(10))

# 查看数据的基本信息
print(data.info())


data['pct'] = data['close'].shift(-1) / data['close'] - 1.0
data['rise'] = data['pct'].apply(lambda x: 1 if x>0 else 0)
#删除缺失值
data = data.dropna()
data.tail(10)

# 查看数据的基本信息
print(data.info())


# 划分训练集和测试集
num_train = round(len(data)*0.8)
data_train = data.iloc[:num_train, :]
data_test = data.iloc[num_train:, :]
# 训练集数据和标签
X_train = data_train[['ema', 'stddev', 'slope', 'rsi', 'wr']].values
y_train = data_train['rise']
# 测试集数据和标签
X_test = data_test[['ema', 'stddev', 'slope', 'rsi', 'wr']].values
y_test = data_test['rise']
print(X_train[:10])
print(45*'-')
print(X_test[:10])



from sklearn.preprocessing import StandardScaler

print('---标准化之前---')
print('训练集的均值：')
print(X_train.mean(axis=0))
print('训练集的标准差：')
print(X_train.std(axis=0))

# 对数据进行标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)

print('---标准化之后---')
print('训练集的均值：')
print(X_train.mean(axis=0))
print('训练集的标准差：')
print(X_train.std(axis=0))


from sklearn.svm import SVC

classifier = SVC(C=1.0, kernel='rbf')
classifier.fit(X_train, y_train)
print(classifier)

y_train_pred = classifier.predict(X_train)
y_test_pred = classifier.predict(X_test)
data_train['pred'] = y_train_pred
data_test['pred'] = y_test_pred
accuracy_train = 100 * data_train[data_train.rise==data_train.pred].shape[0] / data_train.shape[0]
accuracy_test = 100 * data_test[data_test.rise==data_test.pred].shape[0] / data_test.shape[0]
print('训练集预测准确率：%.2f%%' %accuracy_train)
print('测试集预测准确率：%.2f%%' %accuracy_test)



import matplotlib.pyplot as plt

# 设置字体，支持中文显示
plt.rcParams["font.family"] = ["SimHei"]
# 解决负号显示问题（可选）
plt.rcParams["axes.unicode_minus"] = False

#策略日收益率
data_test['strategy_pct'] = data_test.apply(lambda x: x.pct if x.pred>0 else -x.pct, axis=1)
#策略和沪深300的净值
'''
以下代码计算策略和沪深 300 指数净值的方式，是金融分析中计算投资组合净值的标准方法，核心原理是复利累积。
关键逻辑：
每日收益率转换为累积净值
1.0 + data_test['strategy_pct']：将每日收益率（如 5% 转换为 1.05）转换为当日的资金乘数
.cumprod()：对这些乘数进行累积乘积计算，得到每天的累计净值
举例说明
假设我们有 3 天的收益率数据：

日期	策略日收益率 (%)   1 + 收益率	策略净值（cumprod 结果）
第一天	   2%	          1.02	       1.02
第二天	   3%	          1.03	       1.02 × 1.03 = 1.0506
第三天	  -1%	          0.99	       1.0506 × 0.99 ≈ 1.0401

最终净值 1.0401 表示：如果初始投入 1 元，经过 3 天复利增长后变为 1.0401 元，总收益约 4.01%。
为什么这样计算？
符合实际投资逻辑：每天的收益会自动计入本金，参与下一天的收益计算（复利效应）
直观反映收益变化：净值从 1 开始，大于 1 表示盈利，小于 1 表示亏损
便于比较：策略净值与沪深 300 净值可以直接对比，判断策略是否跑赢指数

这种计算方式在基金业绩展示、策略回测中被广泛使用，能最真实地反映投资组合的累积收益情况

'''
data_test['strategy'] = (1.0 + data_test['strategy_pct']).cumprod()
data_test['hs300'] = (1.0 + data_test['pct']).cumprod()
# 粗略计算年化收益率
# 年化收益率 = (最终净值^(250/交易天数) - 1) × 100%
'''
其中：

data_test['strategy'].iloc[-1] 是策略的最终净值
250 是 A 股市场一年的交易日数量（近似值）,A 股回测中，250 是行业通用的交易日基数
data_test.shape[0] 是回测的总交易天数
pow(a, b) 是计算 a 的 b 次方
举例说明
假设我们有一个策略：

回测了 125 个交易日（约半年）
最终净值是 1.15（即半年收益 15%）

代入公式计算：

年化收益率 = (1.15^(250/125) - 1) × 100%
           = (1.15^2 - 1) × 100%
           = (1.3225 - 1) × 100%
           = 32.25%


这表示如果该策略能在全年保持同样的收益水平，年化收益率约为 32.25%。
为什么这样计算？
这种计算方式考虑了复利效应，更贴近实际投资情况。它假设策略在一年的所有交易日中都能保持同样的收益表现，通过复利计算出相当于一年的收益率。

这种方法比简单地将短期收益乘以时间倍数（如半年收益 ×2）更科学，因为它考虑了收益再投资带来的复利增长。

'''
annual_return = 100 * (pow(data_test['strategy'].iloc[-1], 250/data_test.shape[0]) - 1.0)
print('SVM 沪深300指数择时策略的年化收益率：%.2f%%' %annual_return)

#将索引从字符串转换为日期格式，方便展示
data_test.index = pd.to_datetime(data_test.index)
ax = data_test[['strategy','hs300']].plot(figsize=(16,9), color=['SteelBlue','Red'],
                                          title='SVM 沪深300指数择时策略净值')
plt.show()